﻿////////////////////////////////////////////////////////////////
///
/// File: PerfCounter.cs
/// Author: Cristian Dittamo
/// Last update: 11 Dec 2009
/// Description: This file contains the definition of the 
///              main classes needed for performance measurement.
/// To do: 
/// ------------------------------------------------------------
/// Copyright (c) 2009 Cristian Dittamo (dittamo@di.unipi.it)
/// 
/// The use and distribution terms for this software are 
/// contained in the file named license.txt, which can be found 
/// in the root of this distribution.
/// By using this software in any fashion, you are agreeing to 
/// be bound by the terms of this license.
///
/// You must not remove this notice, or any other, from this
/// software.
/// ------------------------------------------------------------
////////////////////////////////////////////////////////////////

using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.ComponentModel;

namespace PerfCounter
{
    public enum MagTime
    {
        sec = 4, //2 decimal places 
        msec = 3, //4 decimal places 
        usec = 2, //8 decimal places 
        nsec = 1  //11 decimal places 
    }

    public class QPerfCounter
    {
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceCounter(out long lpPerformanceCount);
        
        [DllImport("Kernel32.dll")]
        private static extern bool QueryPerformanceFrequency(out long lpFrequency);
        
        private long start;
        private long stop;
        private long frequency;
        private Decimal multiplier;
        private MagTime mt;
        
        public static Hashtable magTime;

        public QPerfCounter(MagTime mag)
        {
            if (QueryPerformanceFrequency(out frequency) == false)
            {
                // Frequency not supported
                throw new Win32Exception();
            }

            mt = mag;
   
            setMultiplier(mt);
        }

        static QPerfCounter()
        {
            magTime = new Hashtable();
            magTime.Add(MagTime.sec, new Decimal(1.0));
            magTime.Add(MagTime.msec, new Decimal(1.0e3));
            magTime.Add(MagTime.usec, new Decimal(1.0e6));
            magTime.Add(MagTime.nsec, new Decimal(1.0e9));
        }

        private void setMultiplier(MagTime m)
        {
            multiplier = (Decimal)magTime[m];
        }

        public void Start()
        {
            QueryPerformanceCounter(out start);
        }

        public void Stop()
        {
            QueryPerformanceCounter(out stop);
        }

        public MagTime Mt
        {
            set { 
                mt = value;
                setMultiplier(mt);
            }
            get { return mt; }
        }

        public Decimal Multiplier { get { return multiplier; } }

        public double Duration(int iterations)
        {
            int decimals = (int)mt;
            Decimal result = ((((stop - start) * multiplier) / frequency) / iterations);
            return (double)Decimal.Round(result,decimals);
        }

        public Decimal Converter(MagTime o, MagTime n)
        {
            return (Decimal)magTime[n] / (Decimal)magTime[o];
        }
    }
}
